﻿#ifndef LK_WINDOWS_UI_TEXTBOX_
#define LK_WINDOWS_UI_TEXTBOX_
#ifndef GWL_WNDPROC
#define GWL_WNDPROC (-4)
#endif
namespace LK
{
	namespace Windows
	{
		namespace UI
		{
			/**
			@brief 表示一个文本框*/
			class ITextBox :public IControl
			{
			public:
				//复制构造，抛出不支持异常
				ITextBox(const ITextBox&) { Throw<PNotSupportException >(); }
				//基类方法
				BMETHODS(PTextBox,ITextBox)
				//构造一个默认的文本窗口
				static LONG_PTR pfun;
				/**
				@brief 创建TextBox，可选的风格参数style有：
				ES_AUTOHSCROLL(水平滚动)，ES_AUTOVSCROLL(垂直滚动)
				ES_CENTER(居中)，ES_LEFT（左对齐），ES_RIGHT（右对齐）
				ES_LOWERCASE（小写），ES_UPPERCASE（大写）
				ES_MULTILINE（多行），ES_WANTRETURN（回车返回）
				ES_NUMBER（数字，创建后可修改）
				ES_OEMCONVERT（转换为OEM字符集，创建后可修改）
				ES_PASSWORD（只适用于单行）
				ES_READONLY（只读，创建后可修改）*/
				ITextBox(HWND hParent,LONG style=0)
					:IControl()
				{
					hMaptc().Lock();//传递指针
					staticPointer = this;
					SetHandle(Create(L"TextBox", Rect(0, 0, 160, 60), L"EDIT", WS_CHILD | WS_VISIBLE | WS_BORDER |style, 0, hParent, NULL));
					hMaptc().UnLock();

					pfun = GetWindowLongPtrW(GetHandle(), GWL_WNDPROC);
					if (pfun == 0)Throw<PWindowsException>(GetLastError());
					if (SetWindowLongPtrW(GetHandle(), GWL_WNDPROC, (LONG_PTR)&StaticWndProc) == 0)Throw<PWindowsException>(GetLastError());
				}

				//重写默认消息处理
				virtual LRESULT DefWndProc(MSG& message);

				//重写消息循环（可重写）
				//virtual void WndProc(MSG& msg){}
				/**
				@brief 获取一个bool值，指示是否可以撤销*/
				bool CanUndo(){ return Edit_CanUndo(GetHandle()) != 0; }
				/**
				@brief 清空撤销缓存*/
				void ResetUndoBuffer(){ Edit_EmptyUndoBuffer(GetHandle()); }
				/**
				@brief 设置可用状态*/
				void SetEnable(bool en){ Edit_Enable(GetHandle(), en); }
				/**
				@brief 设置是否使用\r\n换行*/
				void SetFmtLines(bool en){ Edit_FmtLines(GetHandle(), en); }
				/**
				@brief 获取某一行的字符串*/
				ptr<String> GetLine(int line)
				{
					WCHAR * str;
					int len=GetLineLength(line);
					int mlen = (int)Memory::GetResize((len+2)*sizeof(WCHAR))/sizeof(WCHAR);
					str = new WCHAR[mlen];
					*(int*)str = mlen;
					SendMessageW(GetHandle(), EM_GETLINE, (WPARAM)line, (LPARAM)str);
					return new String(len, str, NULL, mlen);
				}
				/**
				@brief 获取行数*/
				int GetLineCount(){ return Edit_GetLineCount(GetHandle()); }
				/**
				@brief 获取文本是否被修改*/
				bool GetModify(){ return Edit_GetModify(GetHandle())!=0; }
				/**
				@brief 获取密码字符。如果未设置密码字符，则返回0*/
				WCHAR GetPasswordChar(){ return (WCHAR)SendMessageW(GetHandle(), EM_GETPASSWORDCHAR, 0, 0); }
				/**
				@brief pstart用以获取选中内容的起始位置（可选），返回选中字符数*/
				int GetSelection(int* pstart = NULL){ DWORD start, len; SendMessageW(GetHandle(), EM_GETSEL, (WPARAM)&start, (LPARAM)&len); if (pstart)*pstart = start; return len; }
#ifndef ECM_FIRST
#define ECM_FIRST 0x1500
#endif
#ifndef EM_HIDEBALLOONTIP
#define EM_HIDEBALLOONTIP (ECM_FIRST  + 4)
#endif
				/**
				@brief 隐藏气泡提示,操作成功返回true，否则返回false*/
				bool HideBalloonTip(){ return (BOOL)::SendMessageW((GetHandle()), EM_HIDEBALLOONTIP, 0, 0)!=0; }
				/**
				@brief 设置内容长度限制*/
				void SetTextLimit(int maxLength){ ((void)::SendMessageW((GetHandle()), EM_LIMITTEXT, (WPARAM)(maxLength), 0L)); }
				/**
				@brief 获取指定index的字符位置对应行的索引*/
				int GetLineFromChar(int charIndex){ return ((int)(DWORD)::SendMessageW((GetHandle()), EM_LINEFROMCHAR, (WPARAM)(int)(charIndex), 0L)); }
				/**
				@brief 获取指定index行起始位置对应的字符索引*/
				int GetLineIndex(int lineIndex) { return ((int)(DWORD)::SendMessageW(GetHandle(), EM_LINEINDEX, (WPARAM)(int)(lineIndex), 0L)); }
				/**
				@brief 获取指定index行的字符串字符数，当此参数为-1时，将返回未选取内容的字符数*/
				int GetLineLength(int index)
				{
					return (int)SendMessageW(GetHandle(), EM_LINELENGTH, (WPARAM)index, 0);
				}
				/**
				@brief 使用指定的字符串替换已选取的字符串,canUndo参数用以指定该操作是否可以撤销*/
				void ReplaceSelection(ptr<String> const&str,bool canUndo=true)
				{
					SendMessageW(GetHandle(), EM_REPLACESEL,(BOOL)canUndo, (LPARAM)str.ToUnicode());
				}
				/**
				@brief 垂直或水平滚动文本(y为垂直滚动量，x为水平滚动量)*/
				void Scroll(int y, int x){ ((void)::SendMessageW(GetHandle(), EM_LINESCROLL, (WPARAM)(y), (LPARAM)(x))); }
				/**
				@brief 上翻一行*/
				void ScrollLineUp(){ SendMessageW(GetHandle(), EM_SCROLL, SB_LINEUP, 0); }
				/**
				@brief 下翻一行*/
				void ScrollLineDown(){ SendMessageW(GetHandle(), EM_SCROLL, SB_LINEDOWN, 0); }
				/**
				@brief 上翻一页*/
				void ScrollPageUp(){ SendMessageW(GetHandle(), EM_SCROLL, SB_PAGEUP, 0); }
				/**
				@brief 下翻一页*/
				void ScrollPageDown(){ SendMessageW(GetHandle(), EM_SCROLL, SB_PAGEDOWN, 0); }
				/**
				@brief 翻至插入符光标位置*/
				void ScrollCaret(){ Edit_ScrollCaret(GetHandle()); }
#ifndef EM_SETCUEBANNER
#define EM_SETCUEBANNER     (ECM_FIRST + 1) 
#endif
				/**
				@brief 设置内部提示文本，仅对单行文本有效。成功返回true，否则返回false*/
				bool SetCueBannerText(ptr<String> const&str, bool showWhileFocus = false)
				{
					return SendMessageW(GetHandle(), EM_SETCUEBANNER, (WPARAM)showWhileFocus, (LPARAM)str.ToUnicode())!=0;
				}
#ifndef EM_GETCUEBANNER
#define EM_GETCUEBANNER     (ECM_FIRST + 2)  
#endif
				/**
				@brief 获取提示文本*/
				ptr<String> GetCueBanner()
				{
					WCHAR * str;
					int len;
					int mlen = 512;
					for (;;)
					{
						str = new WCHAR[mlen];
						*(int*)str = mlen;
						len = (int)SendMessageW(GetHandle(), EM_GETCUEBANNER, (WPARAM)str, (LPARAM)mlen);
						if (len == 0 && mlen<=65536)
						{
							delete[]str;
							mlen *= 2;
						}
						else break;
					}
					return new String(String::Strlen(str), str, NULL, mlen);
				}
				/**
				@brief 设置文本内容是否改动*/
				void SetModify(bool modified){ Edit_SetModify(GetHandle(), modified); }
				/**
				@brief 设置密码字符*/
				void SetPasswordChar(WCHAR ch){ Edit_SetPasswordChar(GetHandle(), ch); }
				/**
				@brief 设置文本是否只读*/
				void SetReadOnly(bool isReadOnly){ Edit_SetReadOnly(GetHandle(), isReadOnly); }
				/**
				@brief 设置区域大小，但不进行重绘*/
				void SetRectNoPaint(Rect const&rect)
				{
					RECT r = rect;
					Edit_SetRectNoPaint(GetHandle(), &r);
				}
				/**
				@brief 设置选择区域*/
				void SetSelection(int start, int len)
				{
					Edit_SetSel(GetHandle(), start, start+len);
				}
				/**
				@brief 设置Tab间距*/
				void SetTabStops(ptr<LK::Collection::IArray<int>>const&arr)
				{
					Edit_SetTabStops(GetHandle(), arr->size(), ((int*)(int const*)arr));
				}
#ifndef TTI_NONE
#define TTI_NONE 0
				typedef struct _tagEDITBALLOONTIP
				{
					DWORD   cbStruct;
					LPCWSTR pszTitle;
					LPCWSTR pszText;
					INT     ttiIcon; // From TTI_*
				} EDITBALLOONTIP, *PEDITBALLOONTIP;
#define EM_SHOWBALLOONTIP   (ECM_FIRST + 3) 
#endif
				/**
				@brief 显示冒泡提示，tipTitle指定标题，tipText指定提示内容，tIcon指定图标（可选TTI_ERROR、TTI_INFO、TTI_WARNING、TTI_INFO_LARGE、TTI_WARNING_LARGE、TTI_ERROR_LARGE）*/
				bool ShowBalloonTip(ptr<String> const&tipTitle = ptr<String>::GetEmpty(),ptr<String> const&tipText = ptr<String>::GetEmpty(), int tIcon = TTI_NONE)
				{
					EDITBALLOONTIP tip;
					tip.cbStruct = sizeof(EDITBALLOONTIP);
					tip.pszTitle = tipTitle.ToUnicode();
					tip.pszText = tipText.ToUnicode();
					tip.ttiIcon = tIcon;
					return (BOOL)SNDMSG(GetHandle(), EM_SHOWBALLOONTIP, 0, (LPARAM)(&tip))!=0;
				}
				/**
				@brief 撤销一次*/
				void Undo(){ Edit_Undo(GetHandle()); }
				/**
				@brief 获取字符串截断函数*/
				EDITWORDBREAKPROCW GetWordBreakProc()
				{
					return (EDITWORDBREAKPROCW)SendMessageW(GetHandle(), EM_GETWORDBREAKPROC, 0, 0);
				}
				/**
				@brief 设置字符串截断函数*/
				void SetWordBreakProc(EDITWORDBREAKPROCW proc)
				{
					SendMessageW(GetHandle(), EM_SETWORDBREAKPROC ,0,(LPARAM) proc);
				}
			};
			/**
			@brief 表示文本框控件的代理*/
			class PTextBox :public PControl
			{
			public:
				PMETHODS(PTextBox, ITextBox);
				//从父控件进行构造
				//可选的风格参数style有：
				//ES_AUTOHSCROLL(水平滚动)，ES_AUTOVSCROLL(垂直滚动)
				//ES_CENTER(居中)，ES_LEFT（左对齐），ES_RIGHT（右对齐）
				//ES_LOWERCASE（小写），ES_UPPERCASE（大写）
				//ES_MULTILINE（多行），ES_WANTRETURN（回车返回）
				//ES_NUMBER（数字，创建后可修改）
				//ES_OEMCONVERT（转换为OEM字符集，创建后可修改）
				//ES_PASSWORD（只适用于单行）
				//ES_READONLY（只读，创建后可修改）
				PTextBox(PControl const &c,LONG style=0) :PControl(new ITextBox(c.Check()->GetHandle(),style)){}
				/**
				@brief 获取一个bool值，指示是否可以撤销*/
				bool CanUndo(){ return Check()->CanUndo(); }
				/**
				@brief 清空撤销缓存*/
				void ResetUndoBuffer(){ return Check()->ResetUndoBuffer(); }
				/**
				@brief 设置可用状态*/
				void SetEnable(bool en){ Check()->SetEnable(en); }
				/**
				@brief 设置是否使用\r\n换行*/
				void SetFmtLines(bool en){ Check()->SetFmtLines(en); }
				/**
				@brief 获取某一行的字符串*/
				ptr<String> GetLine(int line){ return Check()->GetLine(line); }
				/**
				@brief 获取行数*/
				int GetLineCount(){ return Check()->GetLineCount(); }
				/**
				@brief 获取文本是否被修改*/
				bool GetModify(){ return Check()->GetModify(); }
				/**
				@brief 获取密码字符。如果未设置密码字符，则返回0*/
				WCHAR GetPasswordChar(){ return Check()->GetPasswordChar(); }
				/**
				@brief pstart用以获取选中内容的起始位置（可选），返回选中字符数*/
				int GetSelection(int* pstart = NULL){ return Check()->GetSelection(pstart); }
				/**
				@brief 隐藏气泡提示,操作成功返回true，否则返回false*/
				bool HideBalloonTip(){ return Check()->HideBalloonTip(); }
				/**
				@brief 设置内容长度限制*/
				void SetTextLimit(int maxLength){ Check()->SetTextLimit(maxLength); }
				/**
				@brief 获取指定index的字符位置对应行的索引*/
				int GetLineFromChar(int charIndex){ return Check()->GetLineFromChar(charIndex); }
				/**
				@brief 获取指定index行起始位置对应的字符索引*/
				int GetLineIndex(int lineIndex){ return Check()->GetLineIndex(lineIndex); }
				/**
				@brief 获取指定index行的字符串字符数，当此参数为-1时，将返回未选取内容的字符数*/
				int GetLineLength(int index){ return Check()->GetLineLength(index); }
				/**
				@brief 使用指定的字符串替换已选取的字符串,canUndo参数用以指定该操作是否可以撤销*/
				void ReplaceSelection(ptr<String> const&str, bool canUndo = true){ Check()->ReplaceSelection(str, canUndo); }
				/**
				@brief 垂直或水平滚动文本(y为垂直滚动量，x为水平滚动量)*/
				void Scroll(int y, int x){ Check()->Scroll(y,x); }
				/**
				@brief 上翻一行*/
				void ScrollLineUp(){ Check()->ScrollLineUp(); }
				/**
				@brief 下翻一行*/
				void ScrollLineDown(){ Check()->ScrollLineDown(); }
				/**
				@brief 上翻一页*/
				void ScrollPageUp(){ Check()->ScrollPageUp(); }
				/**
				@brief 下翻一页*/
				void ScrollPageDown(){ Check()->ScrollPageDown(); }
				/**
				@brief 翻至插入符光标位置*/
				void ScrollCaret(){ Check()->ScrollCaret(); }
				/**
				@brief 设置内部提示文本，仅对单行文本框有效。成功返回true，否则返回false*/
				bool SetCueBannerText(ptr<String> const&str, bool showWhileFocus = false){ return Check()->SetCueBannerText(str, showWhileFocus); }
				/**
				@brief 获取提示文本*/
				ptr<String> GetCueBanner(){ return Check()->GetCueBanner(); }
				/**
				@brief 设置文本内容是否改动*/
				void SetModify(bool modified){ Check()->SetModify(modified); }
				/**
				@brief 设置密码字符*/
				void SetPasswordChar(WCHAR ch){ Check()->SetPasswordChar(ch); }
				/**
				@brief 设置文本是否只读*/
				void SetReadOnly(bool isReadOnly){ Check()->SetReadOnly(isReadOnly); }
				/**
				@brief 设置区域大小，但不进行重绘*/
				void SetRectNoPaint(LK::Drawing::Rect<int> const&rect){ Check()->SetRectNoPaint(rect); }
				/**
				@brief 设置选择区域*/
				void SetSelection(int start, int len){ Check()->SetSelection(start,len); }
				/**
				@brief 设置Tab间距*/
				void SetTabStops(ptr<LK::Collection::IArray<int>>const&arr){ Check()->SetTabStops(arr); }
				/**
				@brief 显示冒泡提示，tipTitle指定标题，tipText指定提示内容，tIcon指定图标（可选TTI_ERROR、TTI_INFO、TTI_WARNING、TTI_INFO_LARGE、TTI_WARNING_LARGE、TTI_ERROR_LARGE）*/
				bool ShowBalloonTip(ptr<String> const&tipTitle = ptr<String>::GetEmpty(), ptr<String> const&tipText = ptr<String>::GetEmpty(), int tIcon = TTI_NONE){ return Check()->ShowBalloonTip(tipTitle, tipText, tIcon); }
				/**
				@brief 撤销一次*/
				void Undo(){ Check()->Undo(); }
				/**
				@brief 获取字符串截断函数*/
				EDITWORDBREAKPROCW GetWordBreakProc(){ return Check()->GetWordBreakProc(); }
				/**
				@brief 设置字符串截断函数*/
				void SetWordBreakProc(EDITWORDBREAKPROCW proc){ return Check()->SetWordBreakProc(proc); }
			};
		}
	}
}
#endif
